/**
 * Copyright (c) 2015-2017, Henry Yang 杨勇 (gismail@foxmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lambkit.module.upms.client;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.core.Controller;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.lambkit.Lambkit;
import com.lambkit.core.config.ConfigManager;
import com.lambkit.module.upms.UpmsConfig;
import com.lambkit.module.upms.UpmsManager;
import com.lambkit.plugin.auth.AuthManager;
import com.lambkit.web.LambkitControllerContext;

import com.lambkit.common.util.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SsoAuthenticate {
	static Log log = Log.getLog(SsoAuthenticate.class);
	
//	private static String sessionId;
	
	public static String login(Controller controller) {
		UpmsConfig upmsConfig = ConfigManager.me().get(UpmsConfig.class);
    	Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String sessionId = session.getId().toString();
        String cookie = "lambkit-upms-server-session-id=" + sessionId;
        cookie += "; _jfinal_captcha=" + controller.getCookie("_jfinal_captcha");
        if(Lambkit.isDevMode()) {
        	System.out.println("cookie: " + cookie);
        }
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        Enumeration<String> names = controller.getParaNames();
        for(Enumeration e=names;e.hasMoreElements();){ 
        	String thisName=e.nextElement().toString(); 
            String thisValue=controller.getPara(thisName); 
            nameValuePairs.add(new BasicNameValuePair(thisName, thisValue));
        }
        try {
			return post(upmsConfig.getSsoServerUrl() + "/login", cookie, nameValuePairs);
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return null;
	}
	
	@SuppressWarnings("unused")
	private static String post(String url, String cookie, List<NameValuePair> params) throws ClientProtocolException, IOException {
		HttpClient httpClient = createHttpClient(buildRequestConfig());;
		HttpPost httpPost = new HttpPost(url);
		httpPost.setHeader("cookie", cookie);
		httpPost.setEntity(new UrlEncodedFormEntity(params));
		HttpResponse httpResponse = httpClient.execute(httpPost);
		String result = null;
		if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			HttpEntity httpEntity = httpResponse.getEntity();
			try {
				result = EntityUtils.toString(httpEntity);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				if (httpResponse != null) {
					consumeQuietly(httpResponse.getEntity());
				}
			}
        } 
		return result;
	}
	
	/**
	 * Sub-classes can override specific behaviour of
	 */
	protected static RequestConfig buildRequestConfig() {
		RequestConfig.Builder builder = RequestConfig.custom().setRedirectsEnabled(false)
				//.setCookieSpec(CookieSpecs.IGNORE_COOKIES)
				.setConnectTimeout(3000).setSocketTimeout(3000);
		return builder.build();
	}

	protected static HttpClient createHttpClient(final RequestConfig requestConfig) {
		return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
	}
	
	/**
	 * HttpClient v4.1 doesn't have the method.
	 */
	protected static void consumeQuietly(HttpEntity entity) {
		try {
			EntityUtils.consume(entity);
		} catch (IOException e) {// ignore
			log.error(e.getMessage(), e);
		}
	}
	/**
	 * client模式下，采用http方式实时校验用户
	 * @param controller
	 * @return
	 */
	public static boolean validate(Controller controller) {
		UpmsConfig upmsConfig = ConfigManager.me().get(UpmsConfig.class);
    	Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String sessionId = StrKit.notBlank(getSessionId()) ? getSessionId() : session.getId().toString();
//        String sessionId = session.getId().toString();
        int timeOut = (int) session.getTimeout() / 1000;
        
        Map<String, String> params = new HashMap<String, String>();
    	params.put("appid", upmsConfig.getAppId());
    	params.put("sessionid", sessionId);
        try {
			JSONObject result = JSONObject.parseObject(HttpKit.get(upmsConfig.getSsoServerUrl() + "/authenticate", params));
			if(Lambkit.isDevMode()) {
				System.out.println("result:"+result.getIntValue("code") + ", message:"+result.getString("message") + ", data:" + result.getString("data"));
			}
	        if(result == null || 0 == result.getIntValue("code")) {
	        	// 认证失败
	        	String username = (String) subject.getPrincipal();
                if (StrKit.notBlank(username)) {
                	AuthManager.me().getService().logout(controller.getRequest());
                }
            	return false;
            } else {
            	// 登录状态
            	 String cacheClientSession = UpmsManager.me().getCache().getClientSession(session.getId().toString());
            	 if(StringUtils.isNotBlank(cacheClientSession)) {
            		 //更新code有效期
            		 UpmsManager.me().getCache().refreshClientSession(sessionId, cacheClientSession, timeOut);
            	 } else {
            		 //新增code
            		 cacheClientSession = result.getString("data");
            		// code校验正确，创建局部会话
            		 UpmsManager.me().getCache().saveClientSession(sessionId, cacheClientSession, timeOut);
            	 }
            	 //本地是否登录
                 String username = (String) subject.getPrincipal();
                 if (StrKit.isBlank(username) || username.equals("null")) {
                	// client无密认证
                	 username = result.getString("message");
                	 if(Lambkit.isDevMode()) {
                		 System.out.println("client login: " + username);
                	 }
                	 AuthManager.me().getService().login(controller.getRequest(), username);
                 }
            }
            return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
        return false;
    }
	
	/**
	 * server 模式下的code值
	 * @param sessionId
	 * @return
	 */
	public static String code(String sessionId) {
		// 判断是否已登录，如果已登录，则回跳，防止重复登录
        String code = UpmsManager.me().getCache().getSession(sessionId);
        // code校验值
        return code;
	}
	
	public static String getSessionId() {
		return LambkitControllerContext.get().getAttr("sessionid");
	}

//	public static String getSessionId() {
//		return sessionId;
//	}
//
//	public static void setSessionId(String sessionId) {
//		SsoAuthenticate.sessionId = sessionId;
//	}
	
}
